package aclInfoCollector.filesAnalysers.code.javaFile;

import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Iterator;

import javax.swing.JLabel;
import javax.swing.JTextArea;

import org.apache.ws.jaxme.js.JavaMethod;
import org.apache.ws.jaxme.js.JavaSource;
import org.apache.ws.jaxme.js.JavaSourceFactory;
import org.apache.ws.jaxme.js.Parameter;
import org.apache.ws.jaxme.js.util.JavaParser;

import aclInfoCollector.filesAnalysers.code.CodeFileAnalyser;

import aclInfoCollector.utils.extensionsFilters.DotJavaFilter;
import aclInfoCollector.utils.specialString.StringOperation;
import aclInfoCollector.utils.specialString.StringParameter;

/**
 * La classe JavaFinder permet de reunir les informations contenus dans des
 * fichiers .java
 * 
 * @version 1.0
 * @author Bendavid Olivier
 * @author Haderer Nicolas
 */

public class JavaAnalyser extends CodeFileAnalyser {

	public static void main(String[] args) {
		JavaAnalyser jf = new JavaAnalyser("fractalexplorer");
		//jf.printSummary();
		
		for(String s : jf.getClasses())
		{
				System.out.println("en commun  : "+s);
		}		
	}

	/**
	 * construit un javaFinder initialise les attributs
	 */
	public JavaAnalyser() {
		super();
	}
	/**
	 * construit un javaFinder initialise les attributs et lance une analyse sur
	 * directoryPath
	 */
	public JavaAnalyser(String directoryPath) {
		super(directoryPath);
	}

	
	
	/**
	 * recherche des classes dans un repertoire
	 * 
	 * @param directoryPath
	 *            le chemin du repertoire a analyser
	 * @return la liste des classes trouvées
	 */
	public void launchAnalysis(String directoryPath) {
		File directoryToScan = new File(directoryPath);
		File[] Files = directoryToScan.listFiles();
		FilenameFilter filter = new DotJavaFilter();
		for (int i = 0; i < Files.length; i++) {
			if (Files[i].isDirectory()) {
				launchAnalysis(Files[i].getAbsolutePath());
			}
		}
		File[] FilesJava = directoryToScan.listFiles(filter);
		for (int i = 0; i < FilesJava.length; i++) {
			parse(FilesJava[i]);
		}
	}
	
	

	/**
	
	
	/**
	 * recherche des classes dans un repertoire
	 * 
	 * @param directoryPath
	 *            le chemin du repertoire a analyser
	 * @return la liste des classes trouvées
	 */
	public void launchAnalysis(String directoryPath,JLabel label) {
		File directoryToScan = new File(directoryPath);
		File[] Files = directoryToScan.listFiles();
		FilenameFilter filter = new DotJavaFilter();
		for (int i = 0; i < Files.length; i++) {
			if (Files[i].isDirectory()) {
				launchAnalysis(Files[i].getAbsolutePath());
			}
		}
		File[] FilesJava = directoryToScan.listFiles(filter);
		for (int i = 0; i < FilesJava.length; i++) {
			parse(FilesJava[i],label);
		}
	}
	
	/**
	 * recherche des classes dans un repertoire
	 * 
	 * @param directoryPath
	 *            le chemin du repertoire a analyser
	 * @return la liste des classes trouvées
	 */
	public void launchAnalysis(String directoryPath,JTextArea textArea) {
		File directoryToScan = new File(directoryPath);
		File[] Files = directoryToScan.listFiles();
		FilenameFilter filter = new DotJavaFilter();
		for (int i = 0; i < Files.length; i++) {
			if (Files[i].isDirectory()) {
				launchAnalysis(Files[i].getAbsolutePath());
			}
		}
		File[] FilesJava = directoryToScan.listFiles(filter);
		for (int i = 0; i < FilesJava.length; i++) {
			parse(FilesJava[i],textArea);
		}
	}

	
	/**
	 * 
	 * 
	 * parse le file f
	 */

	public void parse(File f) {
		JavaSourceFactory jsf = new JavaSourceFactory();
		JavaParser jp = new JavaParser(jsf);
		try {
			jp.parse(f);
			for (Iterator<?> iter = jsf.getJavaSources(); iter.hasNext();) {
				JavaSource js = (JavaSource) iter.next();
				if (js.getType().toString().equals("class")) {
					parseClassType(js);
				} else if (js.getType().toString().equals("interface")) {
					parseInterfaceType(js);
				}
			}
		} catch (IllegalStateException e) {
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	
	/**
	 * 
	 * 
	 * parse le file f
	 */

	public void parse(File f, JTextArea textArea) {
		
		JavaSourceFactory jsf = new JavaSourceFactory();
		JavaParser jp = new JavaParser(jsf);
		try {
			textArea.append("\n"+f.getAbsolutePath());
			jp.parse(f);
			for (Iterator<?> iter = jsf.getJavaSources(); iter.hasNext();) {
				JavaSource js = (JavaSource) iter.next();
				if (js.getType().toString().equals("class")) {
					parseClassType(js);
				} else if (js.getType().toString().equals("interface")) {
					parseInterfaceType(js);
				}
			}
		} catch (IllegalStateException e) {
		} catch (Exception e) {
			//label.setText("");
		}
	}
	
	/**
	 * 
	 * 
	 * parse le file f
	 */

	public void parse(File f, JLabel label) {
		
		JavaSourceFactory jsf = new JavaSourceFactory();
		JavaParser jp = new JavaParser(jsf);
		try {
			label.setText(f.getAbsolutePath());
			jp.parse(f);
			for (Iterator<?> iter = jsf.getJavaSources(); iter.hasNext();) {
				JavaSource js = (JavaSource) iter.next();
				  if (js.getType().toString().equals("interface")) {
					parseInterfaceType(js);
				}
				  else if (js.getType().toString().equals("class")) {
						parseClassType(js);
					}
			}
		} catch (IllegalStateException e) {
		} catch (Exception e) {
			//label.setText("");
		}
	}
	
	/**
	 * parse le fichier dont le chemin est le paramétre s
	 */
	public void parse(String s) {
		File f = new File(s);
		JavaSourceFactory jsf = new JavaSourceFactory();
		JavaParser jp = new JavaParser(jsf);
		try {
			jp.parse(f);
			for (Iterator<?> iter = jsf.getJavaSources(); iter.hasNext();) {
				JavaSource js = (JavaSource) iter.next();
				if (js.getType().toString().equals("interface")) {
					parseInterfaceType(js);
				}
				 else if (js.getType().toString().equals("class")) {
						parseClassType(js);
					} 
			}
		} catch (IllegalStateException e) {
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * parse le fichier dont le chemin est le paramétre s
	 */
	public void parse(String s,JLabel label) {
		
		label.setText(s);
		File f = new File(s);
		JavaSourceFactory jsf = new JavaSourceFactory();
		JavaParser jp = new JavaParser(jsf);
		try {
			jp.parse(f);
			for (Iterator<?> iter = jsf.getJavaSources(); iter.hasNext();) {
				JavaSource js = (JavaSource) iter.next();
				 if (js.getType().toString().equals("interface")) {
						parseInterfaceType(js);
					}
				 else if (js.getType().toString().equals("class")) {
						parseClassType(js);
					}
			}
		} catch (IllegalStateException e) {
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	
	
	
	
	
	
	
	/**
	 * parse une javSource correspondant a une class
	 * 
	 * @param js
	 *            la JavaSource a parser
	 */

	public void parseClassType(Object o) {
		JavaSource js = (JavaSource) o;
		addClass(js.getQName().toString());
		if (js.getExtends().length > 0) {
			for (int i = 0; i < js.getExtends().length; i++) {
				if (!classesWithSuperTypes
						.containsKey(js.getQName().toString())) {
					classesWithSuperTypes.put(js.getQName().toString(),
							new ArrayList<String>());
					classesWithSuperTypes.get(js.getQName().toString()).add(
							js.getExtends()[i].toString());
				} else {
					classesWithSuperTypes.get(js.getQName().toString()).add(
							js.getExtends()[i].toString());
				}

			}
		}

		if (js.getImplements().length > 0) {
			for (int i = 0; i < js.getImplements().length; i++) {
				if (!classesWithInterfaces
						.containsKey(js.getQName().toString())) {
					classesWithInterfaces.put(js.getQName().toString(),
							new ArrayList<String>());
					classesWithInterfaces.get(js.getQName().toString()).add(
							js.getImplements()[i].toString());
				} else {
					classesWithInterfaces.get(js.getQName().toString()).add(
							js.getImplements()[i].toString());
				}
			}
		}
	}

	/**
	 * parse une javSource correspondant a une interface
	 * 
	 * @param js
	 *            la javasource a parser
	 */
	public void parseInterfaceType(Object o) {
		JavaSource js = (JavaSource) o;
		String inter = js.getQName().toString();
		
		interfaces.add(inter);
		if (js.getExtends().length > 0) {
			for (int i = 0; i < js.getExtends().length; i++) {
				if (!interfacesWithSuperInterFaces.containsKey(js.getQName()
						.toString())) {
					interfacesWithSuperInterFaces.put(js.getQName().toString(),
							new ArrayList<String>());
					interfacesWithSuperInterFaces.get(js.getQName().toString())
							.add(js.getExtends()[i].toString());
				} else {
					interfacesWithSuperInterFaces.get(js.getQName().toString())
							.add(js.getExtends()[i].toString());
				}
			}
		}
		JavaMethod[] methods = js.getMethods();
		for (int i = 0; i < methods.length; i++) {
			StringOperation strop = new StringOperation();
			strop.setName(methods[i].getName());

			StringParameter spReturn = new StringParameter();
			spReturn.setName(methods[i].getName().toString());
			spReturn.setType(methods[i].getType().toString());
			strop.setReturnType(spReturn);
			for (int d = 0; d < methods[i].getParams().length; d++) {
				Parameter p = methods[i].getParams()[d];
			}
			
			if (methods[i].getType().isPrimitive()) {
				addPrimitive(methods[i].getType().toString());
			}

			ArrayList<StringParameter> temp = new ArrayList<StringParameter>();
			for (int d = 0; d < methods[i].getParamTypes().length; d++) {
				StringParameter sp = new StringParameter();
				sp.setName(methods[i].getParamNames()[d].toString());
				sp.setType(methods[i].getParamTypes()[d].toString().substring(methods[i].getParamTypes()[d].toString().lastIndexOf(".")+1));
				if (methods[i].getParamTypes()[d].isPrimitive()) {
					addPrimitive(methods[i].getParamTypes()[d].toString());
				}
				temp.add(sp);
			}
			strop.setParamsTypes(temp);
			
			if (!interfacesWithOperations.containsKey(inter)) {
				ArrayList<StringOperation> temp2 = new ArrayList<StringOperation>();
				temp2.add(strop);
				interfacesWithOperations.put(inter, temp2);
			} else if (!interfacesWithOperations.get(inter).contains(strop)) {
				interfacesWithOperations.get(inter).add(strop);
			}
		}
	}

}
